using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using DbSetupHelper.Business;
using DbSetupHelper.Common;
using DbSetupHelper.Plugin.ScriptPackage;

namespace DbSetupHelper
{
    /// <summary>
    /// Class used to display the current app.config settings to the user.
    /// </summary>
    public partial class SettingsDialog : Form
    {
        private Collection<DBScript> queue;
        private Collection<SqlPreviewForm> childScreens = new Collection<SqlPreviewForm>();
        private Assembly scriptPackageAssembly;
        private InstallParameters installParameters;

        /// <summary>
        /// Initializes a new instance of the <see cref="SettingsDialog"/> class.
        /// </summary>
        public SettingsDialog(InstallParameters installParameters)
        {
            InitializeComponent();

            txtServer.Text = installParameters.Server;
            txtUserName.Text = installParameters.User;
            txtPassword.Text = installParameters.Password;
            txtDBName.Text = installParameters.DbName;
            txtDBUser.Text = installParameters.DbUserName;
            txtDBPassword.Text = installParameters.DbUserPassword;

            this.installParameters = installParameters;
        }

        /// <summary>
        /// Generates the user install parameters.
        /// </summary>
        /// <returns></returns>
        public InstallParameters GenerateUserInstallParameters()
        {
            InstallParameters retValue = installParameters.Clone();

            //retValue.CancelInstall;
            retValue.DbName = txtDBName.Text;
            retValue.DbUserName = txtDBUser.Text;
            retValue.DbUserPassword = txtDBPassword.Text;
            //retValue.DebugMode;
            //retValue.ExtractDirectory;
            //retValue.ExtractOnly;
            //retValue.InteractiveInstall;
            retValue.Password = txtPassword.Text;
            //retValue.ScriptPackageAssembly;
            //retValue.ScriptPattern;
            retValue.Server = txtServer.Text;
            //retValue.ShowHelp;
            //retValue.TestInstall;
            retValue.User = txtUserName.Text;

            return retValue;
        }

        #region Helper Methods
        private void PopulateAvailableScriptPackages()
        {
            Collection<IScriptPackageMetadata> packages = DatabaseController.Instance.FetchAvailableDbScriptPackages();
            foreach (IScriptPackageMetadata spmd in packages)
            {
                cbAvailablePackages.Items.Add(spmd.PackageFriendlyName);
            }
        }

        private void PopulateScriptList()
        {
            queue = DatabaseController.Instance.FetchDbScriptsForPackage(cbAvailablePackages.Text);
            scriptPackageAssembly = DatabaseController.Instance.FetchAssemblyForScriptPackage(cbAvailablePackages.Text);
            foreach (DBScript script in queue)
            {
                //set the default items. 
                script.SetDatabaseName(txtDBName.Text);
                script.SetDatabaseUserName(txtDBUser.Text);
                script.SetDatabaseUserPassword(txtDBPassword.Text);

                //add the scripts to the check box list. check if enabled. 
                if (script.TestInstall)
                    cblAvailableScripts.Items.Add(script.ScriptFileName, !script.Disabled && installParameters.TestInstall);
                else
                    cblAvailableScripts.Items.Add(script.ScriptFileName, !script.Disabled);
            }

            installParameters.ScriptPattern = queue;
            installParameters.ScriptPackageAssembly = scriptPackageAssembly;
        }
        #endregion

        #region Event Handlers
        private void cblAvailableScripts_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            foreach (DBScript script in queue)
                if (script.ScriptFileName == cblAvailableScripts.Items[e.Index].ToString())
                    script.Disabled = !(e.NewValue == CheckState.Checked);
        }

        private void cbAvailablePackages_SelectedIndexChanged(object sender, EventArgs e)
        {
            cblAvailableScripts.Items.Clear();
            PopulateScriptList();
        }

        private void previewSQLFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (DBScript script in queue)
            {
                if (script.ScriptFileName == cblAvailableScripts.SelectedItem.ToString())
                {
                    SqlPreviewForm form = new SqlPreviewForm(script);
                    childScreens.Add(form);
                    form.FormClosed += new FormClosedEventHandler(form_FormClosed);
                    form.Show();
                    break; //we're done, exit the foreach loop.
                }
            }
        }

        private void form_FormClosed(object sender, FormClosedEventArgs e)
        {
            childScreens.Remove((SqlPreviewForm)sender);
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            if (cblAvailableScripts.SelectedIndex < 0)
                e.Cancel = true;
        }

        private void cblAvailableScripts_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                cblAvailableScripts.SelectedIndex = cblAvailableScripts.IndexFromPoint(e.X, e.Y);
                contextMenuStrip1.Show();
            }
        }

        private void txtDBName_TextChanged(object sender, EventArgs e)
        {
            if (queue != null)
                foreach (DBScript script in queue)
                    script.SetDatabaseName(txtDBName.Text);
        }

        private void txtDBUser_TextChanged(object sender, EventArgs e)
        {
            if (queue != null)
                foreach (DBScript script in queue)
                    script.SetDatabaseUserName(txtDBUser.Text);
        }

        private void txtDBPassword_TextChanged(object sender, EventArgs e)
        {
            if (queue != null)
                foreach (DBScript script in queue)
                    script.SetDatabaseUserPassword(txtDBPassword.Text);
        }

        private void btnRun_Click(object sender, EventArgs e)
        {

            //HACK: There has to be a better way to do this. Find it.
            foreach (DBScript script in queue)
                script.Disabled = true;

            foreach (object o in cblAvailableScripts.CheckedItems)
                foreach (DBScript script in queue)
                    if (script.ScriptFileName == o.ToString())
                        script.Disabled = false;

            while (childScreens.Count > 0)
                childScreens[0].Close();

            this.DialogResult = DialogResult.OK;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            while (childScreens.Count > 0)
                childScreens[0].Close();

            this.DialogResult = DialogResult.Cancel;
        }

        private void btnExtractOnly_Click(object sender, EventArgs e)
        {
            //close all the screens. 
            while (childScreens.Count > 0)
                childScreens[0].Close();

            //user asked us to dump the files to the hard drive.
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            fbd.Description = "Please select an area to save your SQL scripts.";

            if (fbd.ShowDialog() == DialogResult.OK)
            {
                //set member variables
                installParameters.ExtractDirectory = fbd.SelectedPath;
                installParameters.ExtractOnly = true;

                //cleanup our dialog.
                fbd.Dispose();

                this.DialogResult = DialogResult.OK;
            }
        }

        private void SettingsDialog_Shown(object sender, EventArgs e)
        {
            this.Activate();
        }

        private void SettingsDialog_FormClosed(object sender, FormClosedEventArgs e)
        {
            while (childScreens.Count > 0)
                childScreens[0].Close();

            if (e.CloseReason == CloseReason.UserClosing)
            {
                installParameters.CancelInstall = true;
                this.DialogResult = DialogResult.Cancel;
            }
        }

        private void SettingsDialog_Load(object sender, EventArgs e)
        {
            PopulateAvailableScriptPackages();
        }
        #endregion
    }
}
